const { formatDate, formatSequence, getNextSequence } = require('../utils/codeGenerator');
const config = require('../../config');
const codeRules = config.code;
const { getLogger } = require('../logger');
const logger = getLogger('services.codeService');
const { getDbPool } = require('../infra/dbClient');
const db = getDbPool();
/**
 * 编码服务类
 * 负责处理所有编码生成和管理逻辑
 */
class CodeService {
    /**
     * 根据编码规则生成新编码
     * @param {string} codeType - 编码类型
     * @returns {Promise<string>} 生成的编码
     * @throws {Error} 当编码类型无效或生成失败时抛出错误
     */
    static async generateCode(codeType) {
        if (!codeType || !codeRules[codeType]) {
            const errorMsg = `无效的编码类型: ${codeType}`;
            logger.error(errorMsg);
            throw new Error(errorMsg);
        }

        try {
            // 调用generateUniqueCode确保正确处理编码生成
            const code = await this.generateUniqueCode(codeType);
            logger.info(`成功生成编码`, { codeType, code });
            return code;
        } catch (error) {
            logger.error(`生成编码失败: ${error.message}`, { codeType, error: error.stack });
            throw error;
        }
    }

    /**
     * 检查编码是否已存在
     * @param {string} codeType - 编码类型
     * @param {string} code - 要检查的编码
     * @returns {Promise<boolean>} 编码是否存在
     */
    static async checkCodeExists(codeType, code) {
        if (!codeType || !codeRules[codeType] || !code) {
            logger.warn('检查编码参数无效', { codeType, code });
            // 默认认为存在，避免重复
            return true;
        }

        try {
            const exists = await isCodeExists(codeType, code, codeRules);
            logger.debug('编码存在性检查结果', { codeType, code, exists });
            return exists;
        } catch (error) {
            logger.error(`检查编码存在性失败: ${error.message}`, { codeType, code, error: error.stack });
            // 默认认为存在，避免重复
            return true;
        }
    }

    /**
     * 强制生成唯一编码（多次尝试，高可靠）
     * @param {string} codeType - 编码类型
     * @returns {Promise<string>} 生成的唯一编码
     * @throws {Error} 当编码类型无效或生成失败时抛出错误
     */
    static async generateUniqueCode(codeType) {
        if (!codeType || !codeRules[codeType]) {
            const errorMsg = `无效的编码类型: ${codeType}`;
            logger.error(errorMsg);
            throw new Error(errorMsg);
        }
        
        try {
            // 优先使用forceGenerateCode，它内部已经包含多次尝试和兜底逻辑
            const code = await forceGenerateCode(codeType, codeRules);
            logger.info(`成功强制生成唯一编码`, { codeType, code });
            return code;
        } catch (error) {
            logger.error(`强制生成唯一编码失败: ${error.message}`, { codeType, error: error.stack });
            throw error;
        }
    }

    /**
     * 初始化序列号表（自动创建缺失的初始记录）
     * @returns {Promise<void>}
     */
    static async initSequenceTable() {
        logger.info('开始初始化序列号表...');
        const datePart = new Date().toISOString().slice(0, 10).replace(/-/g, '');

        try {
            // 为每种编码类型初始化当天的序列号
            for (const codeType of Object.keys(codeRules)) {
                const sequenceKey = `${codeType}_${datePart}`;

                // 直接插入记录并设置current_value为0，而不是调用getNextSequence
                // 这样第一条实际使用时会从1开始（0+1）
                try {
                    // 使用正确的数据库连接模块

                    await db.execute(`
            INSERT INTO sequence_counter (code_type, current_value, update_time)
            VALUES (?, 0, NOW())
            ON DUPLICATE KEY UPDATE update_time = NOW()
          `, [sequenceKey]);
                    logger.info(`初始化${codeType}编码类型的序列号表，设置初始值为0`, { sequenceKey });
                } catch (error) {
                    logger.warn(`初始化${codeType}编码类型的序列号表失败`, { error, sequenceKey });
                }
            }
            logger.info('✅ 序列号表初始化完成');
        } catch (error) {
            logger.warn('序列号表初始化失败，但不影响服务运行', { error });
        }
    }

    /**
     * 获取编码规则配置
     * @param {string} codeType - 编码类型，如果不提供则返回所有规则
     * @returns {object} 编码规则配置
     */
    static getCodeRule(codeType) {
        if (codeType) {
            return codeRules[codeType];
        }
        return codeRules;
    }

    /**
     * 批量生成编码
     * @param {string} codeType - 编码类型
     * @param {number} count - 生成数量
     * @returns {Promise<string[]>} 生成的编码数组
     * @throws {Error} 当编码类型无效或生成失败时抛出错误
     */
    static async batchGenerateCode(codeType, count = 1) {
        if (!codeType || !codeRules[codeType]) {
            const errorMsg = `无效的编码类型: ${codeType}`;
            logger.error(errorMsg);
            throw new Error(errorMsg);
        }

        if (!count || count <= 0 || count > 100) {
            throw new Error('生成数量必须在1-100之间');
        }

        const codes = [];
        try {
            for (let i = 0; i < count; i++) {
                const code = await this.generateUniqueCode(codeType);
                codes.push(code);
            }
            logger.info(`成功批量生成编码`, { codeType, count, codes });
            return codes;
        } catch (error) {
            logger.error(`批量生成编码失败: ${error.message}`, { codeType, count, error: error.stack });
            throw error;
        }
    }
}

module.exports = CodeService;

/**
 * 生成编码的底层实现
 * @param {string} sequenceKey - 序列号键
 * @param {string} prefix - 编码前缀
 * @param {string} datePart - 日期部分
 * @param {number} sequenceLength - 序列号长度
 * @param {string} table - 表名（降级时使用）
 * @param {string} field - 字段名（降级时使用）
 * @returns {Promise<string>}
 */
async function generateCode(sequenceKey, prefix, datePart, sequenceLength, table, field) {
    const logger = getLogger('services.codeService');
    logger.info('开始生成编码', { sequenceKey, prefix, datePart, sequenceLength });

    // 参数验证
    if (!sequenceKey || typeof sequenceKey !== 'string') {
        throw new Error('序列号键无效');
    }

    if (!sequenceLength || isNaN(sequenceLength) || sequenceLength < 1) {
        throw new Error('序列号长度无效');
    }

    try {
        logger.debug('尝试获取序列号', { sequenceKey, sequenceLength });

        // 优先使用序列号表（原子操作，更可靠）
        let nextSequence = await getNextSequence(sequenceKey, sequenceLength);
        logger.info(`成功获取序列号: ${nextSequence}`, { sequenceKey });

        // 移除取模操作，确保序列号严格递增
        logger.debug('格式化序列号', { nextSequence, sequenceLength });
        const formattedSequence = formatSequence(nextSequence, sequenceLength);

        // 组合编码
        logger.debug('组合编码各部分', { prefix, datePart, formattedSequence });
        const safePrefix = prefix || '';
        const code = safePrefix ? `${safePrefix}${datePart}${formattedSequence}` : `${datePart}${formattedSequence}`;

        logger.debug(`生成完整编码: ${code}`, {
            prefix: safePrefix,
            datePart,
            formattedSequence,
            codeLength: code.length
        });

        logger.info(`成功生成编码: ${code}`, { sequenceKey });
        return code;
    } catch (error) {
        logger.error(`生成编码失败，将使用降级方案`, {
            error: error,
            sequenceKey,
            stack: error.stack?.substring(0, 200)
        });

        // 降级方案：使用传统的最大序列号+1方法
        if (!table || !field) {
            logger.debug('未提供表信息，使用内存计数器作为降级方案', { sequenceKey });

            // 如果没有提供表和字段信息，使用内存计数器作为降级方案
            try {
                logger.debug('初始化内存计数器系统', { sequenceKey });

                // 确保全局计数器对象正确初始化
                if (typeof global.sequenceCounters !== 'object' || global.sequenceCounters === null) {
                    global.sequenceCounters = {};
                    logger.debug('创建新的全局序列计数器对象');
                }

                // 为特定序列键初始化计数器
                if (typeof global.sequenceCounters[sequenceKey] !== 'number') {
                    global.sequenceCounters[sequenceKey] = 0;
                    logger.debug(`初始化序列计数器: ${sequenceKey} = 0`);
                }

                // 递增计数器
                global.sequenceCounters[sequenceKey] += 1;
                const counterValue = global.sequenceCounters[sequenceKey];
                logger.debug(`内存计数器递增: ${sequenceKey} = ${counterValue}`);

                const formattedSequence = formatSequence(counterValue, sequenceLength);
                const safePrefix = prefix || '';
                const fallbackCode = safePrefix ? `${safePrefix}${datePart}${formattedSequence}` : `${datePart}${formattedSequence}`;
                logger.info(`使用内存计数器生成编码: ${fallbackCode}`, { sequenceKey, counterValue });
                return fallbackCode;
            } catch (counterError) {
                logger.error('内存计数器降级方案失败', {
                    counterError: counterError.message,
                    sequenceKey,
                    stack: counterError.stack?.substring(0, 200)
                });

                // 最终降级：使用时间戳+随机数确保唯一性
                logger.debug('使用最终降级方案：时间戳+随机数', { sequenceKey });
                const timestamp = Date.now();
                const random = Math.floor(Math.random() * 10000).toString().padStart(4, '0');
                const safePrefix = prefix || '';
                const emergencyCode = safePrefix ? `${safePrefix}${datePart}${random}` : `${datePart}${random}`;
                logger.warn(`使用紧急降级方案生成编码: ${emergencyCode}`, { sequenceKey });
                return emergencyCode;
            }
        }

        logger.debug('使用表查询作为降级方案', { sequenceKey, table, field });
        const safePrefix = prefix || '';
        const likePattern = safePrefix ? `${safePrefix}${datePart}%` : `${datePart}%`;

        logger.debug('查询数据库获取最大序列号', {
            table,
            field,
            likePattern,
            prefixLength: safePrefix.length,
            datePartLength: datePart.length
        });

        const maxSequence = await getMaxSequenceFromDB(
            table,
            field,
            likePattern,
            safePrefix.length,
            datePart.length
        );

        logger.debug('计算新序列号', { maxSequence, newSequence: maxSequence + 1 });
        const newSequence = maxSequence + 1;
        const formattedSequence = formatSequence(newSequence, sequenceLength);

        const code = safePrefix ? `${safePrefix}${datePart}${formattedSequence}` : `${datePart}${formattedSequence}`;
        logger.info(`使用降级方案生成编码: ${code}`, { sequenceKey });
        return code;
    } finally {
        logger.debug('编码生成过程结束', { sequenceKey });
    }
}

/**
 * 从数据库获取当前最大序列号（兼容旧方案）
 * @param {string} table - 表名
 * @param {string} field - 字段名
 * @param {string} likePattern - 查询模式
 * @param {string} prefixLength - 前缀长度
 * @param {string} datePartLength - 日期部分长度
 * @returns {Promise<number>} 当前最大序列号
 */
async function getMaxSequenceFromDB(table, field, likePattern, prefixLength, datePartLength) {
    try {
        const sql = `
      SELECT MAX(${field}) as maxCode 
      FROM ${table} 
      WHERE ${field} LIKE ? AND is_delete = 0
    `;

        logger.debug('尝试获取最大序列号', { table, field, likePattern });
        const [rows] = await db.execute(sql, [likePattern]);

        if (!rows[0].maxCode) {
            logger.debug('未找到匹配的编码，从0开始', { table, field, likePattern });
            return 0; // 如果没有找到匹配的编码，从0开始
        }

        // 提取序列号部分
        const code = rows[0].maxCode;
        const sequencePart = code.substring(prefixLength + datePartLength);
        const maxSequence = parseInt(sequencePart) || 0;

        logger.debug(`获取到最大序列号: ${maxSequence}`, { table, field, code });
        return maxSequence;
    } catch (error) {
        logger.error('从数据库获取最大序列号失败', { error, table, field });
        return 0;
    }
}

/**
 * 生成兜底编码（当其他方法都失败时使用）
 * @param {string} codeType - 编码类型
 * @param {string} prefix - 编码前缀
 * @returns {string} 生成的编码
 */
function generateLastResortCode(codeType, prefix = '') {
    const logger = getLogger('services.codeService');
    logger.debug('使用兜底方案生成编码', { codeType, prefix });

    // 确保参数有效
    const safePrefix = prefix && typeof prefix === 'string' ? prefix : '';
    const safeCodeType = codeType && typeof codeType === 'string' ? codeType : 'UNKNOWN';

    // 使用时间戳+随机数确保唯一性
    const timestamp = Date.now();
    const random = Math.floor(Math.random() * 10000);

    const code = `${safePrefix}RESERVED${safeCodeType}${timestamp}${random}`;

    logger.warn(`生成兜底编码: ${code}`, {
        codeType,
        timestampLength: timestamp.toString().length,
        randomLength: random.toString().length,
        codeLength: code.length
    });

    return code;
}

/**
 * 检查编码是否存在
 * @param {string} codeType - 编码类型
 * @param {string} code - 要检查的编码
 * @param {object} codeRules - 编码规则配置
 * @returns {Promise<boolean>} 编码是否存在
 */
async function isCodeExists(codeType, code, codeRules) {
    const logger = getLogger('services.codeService');
    logger.debug('检查编码是否存在', { codeType, code });

    // 参数验证
    if (!codeType || !code || !codeRules) {
        logger.warn('检查编码存在性失败：缺少必要参数', {
            hasCodeType: !!codeType,
            hasCode: !!code,
            hasCodeRules: !!codeRules
        });
        return true; // 保守返回存在，避免创建重复编码
    }

    const rule = codeRules[codeType];
    if (!rule || !rule.table || !rule.field) {
        logger.debug('无法检查编码存在性：缺少表信息或字段信息', {
            codeType,
            hasRule: !!rule,
            hasTable: !!rule?.table,
            hasField: !!rule?.field
        });
        return false; // 无表配置时认为不存在
    }

    try {
        const sql = `SELECT COUNT(1) as count FROM ${rule.table} WHERE ${rule.field} = ? AND is_delete = 0`;

        logger.debug('执行SQL检查编码存在性', {
            codeType,
            code,
            table: rule.table,
            field: rule.field
        });

        const [rows] = await db.execute(sql, [code]);
        const exists = rows[0].count > 0;

        logger.info(`编码检查结果：${code} ${exists ? '已存在' : '不存在'}`, {
            codeType,
            code,
            exists
        });

        return exists;
    } catch (error) {
        logger.error('检查编码存在性失败', {
            error: error,
            codeType,
            code,
            table: rule.table,
            field: rule.field,
            stack: error.stack?.substring(0, 200)
        });
        // 发生错误时保守返回true，避免创建重复编码
        return true;
    }
}

/**
 * 强制生成唯一编码（多次尝试）
 * @param {string} codeType - 编码类型
 * @param {object} codeRules - 编码规则配置
 * @returns {Promise<string>} 生成的唯一编码
 */
async function forceGenerateCode(codeType, codeRules) {
    const logger = getLogger('services.codeService');
    logger.info(`开始强制生成编码: ${codeType}`, { codeType });

    // 参数验证
    if (!codeType || typeof codeType !== 'string') {
        throw new Error('编码类型参数无效');
    }

    if (!codeRules || typeof codeRules !== 'object') {
        throw new Error('编码规则参数无效');
    }

    const rule = codeRules[codeType];
    if (!rule) {
        logger.error(`无效的编码类型: ${codeType}`);
        throw new Error(`无效的编码类型: ${codeType}`);
    }

    // 记录规则详情（注意敏感信息脱敏）
    logger.debug('编码规则详情', {
        codeType,
        prefix: rule.prefix,
        pattern: rule.pattern,
        sequenceLength: rule.sequenceLength,
        hasTable: !!rule.table,
        hasField: !!rule.field
    });

    const maxRetries = 5;
    logger.info(`设置最大重试次数: ${maxRetries}`, { codeType });

    try {
        // 检查是否启用自动补全已删除编码功能（默认为false）
        const enableAutoComplete = rule.autoComplete === true;
        logger.debug('自动补全功能配置', { codeType, enableAutoComplete });

        // 只有在明确启用时才尝试查找可重用的已删除编码
        if (enableAutoComplete) {
            logger.debug('尝试查找可重用的已删除编码', { codeType });
            const reusedCode = await findDeletedCodeToReuse(codeType, rule);
            if (reusedCode) {
                logger.info(`成功重用已删除的编码: ${reusedCode}`, { codeType });
                return reusedCode;
            }
            logger.debug('未找到可重用的已删除编码，继续生成新编码', { codeType });
        }
        logger.debug('自动补全功能未启用，直接生成新编码', { codeType });

        // 如果没有可重用的编码，使用常规生成方式
        for (let attempt = 1; attempt <= maxRetries; attempt++) {
            logger.info(`生成编码尝试 ${attempt}/${maxRetries}`, { codeType });
            try {
                const datePart = formatDate(rule.pattern);
                const sequenceKey = `${codeType}_${datePart}`;

                logger.debug('准备生成编码', { codeType, datePart, sequenceKey });

                // 生成新编码
                const code = await generateCode(
                    sequenceKey,
                    rule.prefix,
                    datePart,
                    rule.sequenceLength,
                    rule.table,
                    rule.field
                );

                logger.debug(`成功生成候选编码: ${code}`, { codeType });

                // 再次确认编码唯一性
                logger.debug('验证编码唯一性', { codeType, code });
                const exists = await isCodeExists(codeType, code, codeRules);
                if (!exists) {
                    logger.info(`编码唯一性验证通过: ${code}`, { codeType });
                    return code;
                }

                logger.warn(`生成的编码已存在，尝试第 ${attempt + 1} 次`, { codeType, code });
            } catch (error) {
                logger.error(`生成编码尝试 ${attempt} 失败`, {
                    error: error,
                    codeType,
                    stack: error.stack?.substring(0, 200) // 只记录部分堆栈信息
                });
            }
        }

        // 多次尝试失败后使用兜底方案
        logger.warn(`多次生成编码失败 (${maxRetries}次)，使用兜底方案`, { codeType });
        const fallbackCode = generateLastResortCode(codeType, rule.prefix);
        logger.info(`使用兜底方案生成编码: ${fallbackCode}`, { codeType });
        return fallbackCode;
    } catch (error) {
        logger.error('强制生成编码过程中发生未预期错误', {
            error: error,
            codeType,
            stack: error.stack?.substring(0, 200)
        });
        // 最后一道防线
        return generateLastResortCode(codeType, rule.prefix || 'ERROR');
    } finally {
        logger.debug('强制生成编码过程结束', { codeType });
    }
}

/**
 * 查找已删除但可以重用的编码
 * @param {string} codeType - 编码类型
 * @param {object} rule - 编码规则
 * @returns {Promise<string|null>} 可重用的编码或null
 */
async function findDeletedCodeToReuse(codeType, rule) {
    const logger = getLogger('services.codeService');
    logger.debug('开始查找可重用的已删除编码', { codeType });

    // 参数验证
    if (!codeType || !rule) {
        logger.warn('查找可重用编码失败：缺少必要参数', { codeType: !!codeType, hasRule: !!rule });
        return null;
    }

    if (!rule.table || !rule.field) {
        logger.debug('无法重用编码：缺少表信息或字段信息', {
            codeType,
            hasTable: !!rule.table,
            hasField: !!rule.field
        });
        return null;
    }

    try {
        const datePart = formatDate(rule.pattern);
        const safePrefix = rule.prefix || '';
        const likePattern = safePrefix ? `${safePrefix}${datePart}%` : `${datePart}%`;

        logger.debug('查询可重用的已删除编码', {
            codeType,
            table: rule.table,
            field: rule.field,
            likePattern
        });

        const sql = `
      SELECT ${rule.field} as code 
      FROM ${rule.table} 
      WHERE ${rule.field} LIKE ? AND is_delete = 1 
      ORDER BY ${rule.field} ASC 
      LIMIT 1
    `;

        const [rows] = await db.execute(sql, [likePattern]);

        if (!rows || rows.length === 0) {
            logger.debug('未找到可重用的已删除编码', { codeType });
            return null;
        }

        const reusedCode = rows[0].code;
        logger.info(`找到可重用的已删除编码: ${reusedCode}`, { codeType });

        // 更新编码状态为未删除，以便重用
        await db.execute(
            `UPDATE ${rule.table} SET is_delete = 0 WHERE ${rule.field} = ?`,
            [reusedCode]
        );

        logger.info(`已重用编码并更新状态: ${reusedCode}`, { codeType });
        return reusedCode;
    } catch (error) {
        logger.error('查找可重用编码失败', {
            error: error,
            codeType,
            hasTable: !!rule.table,
            hasField: !!rule.field,
            stack: error.stack?.substring(0, 200)
        });
        return null;
    }
}

// 导出CodeService类和这些函数供其他模块使用
module.exports = CodeService;
module.exports.generateCode = generateCode;
module.exports.isCodeExists = isCodeExists;
module.exports.forceGenerateCode = forceGenerateCode;
module.exports.findDeletedCodeToReuse = findDeletedCodeToReuse;
module.exports.getMaxSequenceFromDB = getMaxSequenceFromDB;
module.exports.generateLastResortCode = generateLastResortCode;